﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BearUtil.Hidden;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using UnityEditor;
using UnityEngine;
using XNode;
using XNodeEditor;
using Object = System.Object;

namespace BearUtil
{
    /// <summary>
    /// 剧情片段
    /// </summary>
    [NodeGraphEditor.CustomNodeGraphEditorAttribute(typeof(StoryGraph))]
    [Serializable, RequireNode(typeof(StartNode), typeof(EndNode))]
    public class StoryGraph : XNode.NodeGraph, ICustomSetting, ICustomGraph
    {
        [BoxGroup("基本属性"), HideLabel] public BasicProperty basic;

        #region Setting

        public string AddName
        {
            get { return "导出 Excel"; }
            set { }
        }

        public string RemoveName
        {
            get { return "删除 Excel"; }
            set { }
        }

        [HideInInspector, SerializeField] public int genCount = 0;

        // 编辑器上一次停留位置
        [HideInInspector] public Vector2 LastFocusPosition;

        /// <summary>
        /// 导出 Excel 数据
        /// </summary>
        /// <param name="window"></param>
        public void Add(OdinMenuEditorWindow window)
        {
            // 全部 dialog 遍历
        }

        /// <summary>
        /// 删除 Excel 数据
        /// </summary>
        /// <param name="selected"></param>
        public void Remove(OdinMenuItem selected)
        {
            // 移除全部 excel
        }

        #endregion

        public StoryGraph()
        {
            if (basic == null)
                basic = new BasicProperty();

            if (basic.audioData.SyncFontSpeedCallback == null)
                basic.audioData.SyncFontSpeedCallback = SyncFontSpeed;
        }

        public void UpdateData()
        {
            // reset node index
            for (int i = 0; i < nodes.Count(); i++)
            {
                var bn = (nodes[i] as BearNode);
                if (bn == null)
                {
                    nodes.RemoveAt(i);
                    i--;
                    continue;
                }

                bn.index = i + 1;
            }
        }

        /// <summary>
        /// 添加接点时
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public override Node AddNode(Type type)
        {
            Node node = null;
            genCount++;
            // 设置 index
            if (type.InheritsFrom(typeof(BearDialog)))
            {
                node = base.AddNode(type);
                BearDialog bn = (node as BearDialog);

                bn.id = genCount;
                bn.name = name + "_" + type.Name + "_" + genCount;
                basic.Clone(ref bn.basic);
                // 设置 scriptObject 关联
                bn.BindGraph(GenerateScriptObject(bn) as DialogGraph);
            }
            else
            {
                node = base.AddNode(type);
            }

            UpdateData();

            return node;
        }

        public override Node CopyNode(Node original)
        {
            genCount++;
            Node node = null;
            var type = original.GetType();
            if (type.InheritsFrom(typeof(BearDialog)))
            {
                node = base.CopyNode(original);
                BearDialog bn = (node as BearDialog);
                bn.id = genCount;
                bn.name = name + "_" + genCount.ToString();
                basic.Clone(ref bn.basic);
                // 设置 scriptObject 关联
                bn.BindGraph(GenerateScriptObject(bn) as DialogGraph);
            }
            else
            {
                node = base.CopyNode(original);
            }

            UpdateData();

            return node;
        }

        public override void RemoveNode(Node node)
        {
            base.RemoveNode(node);
            UpdateData();
        }

        /// <summary>
        /// 创建 dialog 需要的 graph
        /// </summary>
        private const string dialogPath = "Assets/StoryEditor/Nodes/Dialogs/Data/";

        private ScriptableObject GenerateScriptObject(BearNode node)
        {
            StringBuilder sb = new StringBuilder(dialogPath);
            sb.Append(name);
            sb.Append("/");

            string dir = sb.ToString();
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
                AssetDatabase.Refresh();
            }

            sb.Append(node.name);
            sb.Append("_graph.asset");
            Type dgType = typeof(DialogGraph);
            var graph = ScriptableObject.CreateInstance(dgType);

            string path = sb.ToString();
            var asset = AssetDatabase.LoadAssetAtPath(path, dgType);
            if (asset != null)
                AssetDatabase.DeleteAsset(path);

            AssetDatabase.CreateAsset(graph, path);
            AssetDatabase.Refresh();

            return graph;
        }

        private void SyncFontSpeed()
        {
            for (var i = 0; i < nodes.Count; i++)
            {
                var node = nodes[i] as BearDialog;
                if (node == null)
                    continue;

                node.basic.audioData.FontSpeed = basic.audioData.FontSpeed;
                node.SyncFontSpeed();
            }
        }

        /// <summary>
        /// 找到链式节点
        /// </summary>
        /// <returns></returns>
        private List<BearNode> FindLinks()
        {
            List<BearNode> close = new List<BearNode>();
            EndNode end = null;
            for (var i = 0; i < nodes.Count; i++)
            {
                end = nodes[i] as EndNode;
                if (end != null)
                    break;
            }

            Node last = end?.Inputs.First().GetConnections().FirstOrDefault().node;
            
            while (last != null)
            {
                var dn = last as BearNode;
                if (dn == null)
                    dn = last as BearPrefix;
                if (dn == null || !dn.GetType().Name.Equals("StartNode"))
                    close.Add(dn);

                last = last?.Inputs.First().GetConnections().FirstOrDefault()?.node;
            }

            close.Reverse();
            return close;
        }

        #region 暂时不用

        /// <summary>
        /// 输出数据
        /// </summary>
        //[Button("输出 Story 章节数据", ButtonSizes.Large)]
        public void GenerateStoryData()
        {
            UpdateData();
            List<FormatData> sdfs = new List<FormatData>();
            var close = FindLinks();
            for (int i = 0; i < close.Count; i++)
            {
                var node = close[i];
                if (node)
                {
                    // FormatDataUtil.SetData(ref FormatData fd, node);
                    // sdfs.Add(fd);
                    // // s_ 适应 lua table 明明需求
                    // fd.index = $"s_{basic.id}_{node.basic.id}";
                }
                else
                {
                    try
                    {
                        if (!node.GetType().Name.Contains("StartNode") && !node.GetType().Name.Contains("EndNode"))
                            Debug.LogError("Error DialogNode Data:" + close[i].name);
                    }
                    catch
                    {
                        var dialogName = node == null ? i.ToString() : node.name;
                        Debug.LogError($"StoryName: {name}; DialogName: {dialogName}");
                    }
                }
            }

            generateStoryExcel(sdfs);
        }

        /// <summary>
        /// 生成 story dialogue.xls
        /// </summary>
        /// <param name="sdfs"></param>
        private void generateStoryExcel(List<FormatData> sdfs)
        {
            var excelData = ExcelDataGenerator.GenerateExcelData<FormatData>(sdfs);
            if (excelData == null)
                return;

            excelData.sheetName = name;
            Utils.CreateScriptableObject(excelData, ExcelDataGenerator.Instance.StoriesDataPath, name);

            string foldPath = ExcelDataGenerator.Instance.OutputExcelFold + "/" + "章节";
            ExcelEdit.WriteExcel(excelData, foldPath);
        }

        #endregion

        /// <summary>
        ///  采集所有故事的 formatdata 信息
        /// </summary>
        /// <returns></returns>
        public List<FormatData> CollectAllFormatData()
        {
            UpdateData();
            List<FormatData> fds = new List<FormatData>();
            var close = FindLinks();
            for (int i = 0; i < close.Count; i++)
            {
                var node = close[i];
                if (node)
                {
                    var typeName = node.GetType().Name + "Format";
                    FormatData fd = (FormatData) Activator.CreateInstance(FormatDataUtil.GetType(typeName));
                    FormatDataUtil.SetData(ref fd, node);

                    var dialogueNode = node as BearDialog;
                    var prefixNode = node as BearPrefix;
                    if (dialogueNode != null)
                    {
                        // // s_ 适应 lua table 明明需求
                        var indexProp = fd.GetType().GetField("index");
                        var indexValue =  $"s_{basic.id}_{dialogueNode.basic.id}";
                        indexProp.SetValue(fd, indexValue);
                        // 作为固定属性，临时写在这 format 需要复制，但是 node 里面不包含对应数据
                        try
                        {
                            fd.GetType().GetField(FormatDataUtil.episode_id).SetValue(fd, Convert.ToInt32(basic.id));
                            fd.GetType().GetField(FormatDataUtil.dialogue_id).SetValue(fd,
                                dialogueNode.basic.id.Trim().Equals("") ? 0 : Convert.ToInt32(dialogueNode.basic.id));
                            fd.GetType().GetField(FormatDataUtil.remark).SetValue(fd, dialogueNode.basic.name);
                        }
                        catch (Exception e)
                        {
                            Debug.LogError("StoryGraph 配置出错, 请检查 Dialog Node 数据");
                            Debug.LogError(e);
                        }
                        
                        fds.Add(fd);
                    }
                    else if (prefixNode != null)
                    {
                        /// prefix node 前置节点
                        var nodePort = prefixNode.Outputs.First().GetConnections().First();
                        var bn = nodePort.node as BearDialog;
                        if (bn == null)
                        {
                            Debug.LogError("[CreateNewPrefix] 连接节点错误");
                            break;
                        }

                        // // s_ 适应 lua table 明明需求
                        var indexProp = fd.GetType().GetField("index");
                        var indexValue =  $"s_{basic.id}_{bn.basic.id}";
                        indexProp.SetValue(fd, indexValue);
                        
                        fds.Add(fd);
                    }
                }
                else
                {
                    try
                    {
                        if (!node.GetType().Name.Contains("StartNode") && !node.GetType().Name.Contains("EndNode"))
                            Debug.LogError("Error DialogNode Data:" + close[i].name);
                    }
                    catch
                    {
                        var dialogName = node == null ? i.ToString() : node.name;
                        Debug.LogError($"StoryName: {name}; DialogName: {dialogName}");
                    }
                }
            }

            return fds;
        }

        [Button("输出 Dialog 节点内数据", ButtonSizes.Large)]
        public void GenerateDialogData()
        {
            var links = FindLinks();
            for (int i = 0; i < links.Count; i++)
            {
                var dn = links[i] as BearDialog;
                if (dn && dn.selfGraph != null)
                    dn.selfGraph.OutputData();
            }
        }
    }
}